import unittest
from directions import Directions
from map import Directions, Map
import louie
import pickle

class MapTest(unittest.TestCase):
    def setUp(self):
        self.m = Map()
    def testGetCellCheckBounds(self):
        """Raise exception if cell is out of bounds"""
        self.assertRaises(IndexError, self.m.getCell, -1,-1)
        self.assertRaises(IndexError, self.m.getCell, -1, 0)
        self.assertRaises(IndexError, self.m.getCell, self.m.width, 0)
        self.assertRaises(IndexError, self.m.getCell, 0, self.m.height)
        self.assertRaises(IndexError, self.m.getCell, self.m.width, self.m.height)
        self.assertRaises(IndexError, self.m.getCell, 100, 100)
        self.m.getCell(0,0)
        self.m.getCell(self.m.width - 1, self.m.width - 1)

    def testGetCell(self):
        """ getCell should get the correct cell """
        for (x,y) in [(x,y) for y in range(self.m.height) for x in range(self.m.width)]:
            assert self.m.getCell(x, y).pos == (x, y)

class CellTest(unittest.TestCase):

    def setUp(self):
        self.map = Map()
        self.DEBUG = False

    def process(self, verify):
        for (x,y) in [(x,y) for y in range(self.map.height) for x in range(self.map.width)]:
            cur = self.map.getCell(x,y)
            if (x > 0): verify(cur, self.map.getCell(x - 1, y), Directions.West)
            if (x < self.map.width - 1): verify(cur, self.map.getCell(x + 1, y), Directions.East)
            if (y > 0): verify(cur, self.map.getCell(x, y - 1), Directions.North)
            if (y < self.map.height - 1): verify(cur, self.map.getCell(x, y + 1), Directions.South)

    def testWallConnectivity(self):
        """ Walls between cell must map to the same wall"""
        def verify(cell1, cell2, dir):
            orig = cell1.getWall(dir)
            assert cell2.getWall(~dir) == orig
            cell2.setWall(~dir, orig + 'TEST')
            assert cell1.getWall(dir) == orig + 'TEST'
            cell1.setWall(dir, orig)
            assert cell2.getWall(~dir) == orig
        self.process(verify)

    def testWallProperties(self):
        """Wall properties should function like set/getWall"""
        cnt = [0]
        def verify(c, other, dir):
            cnt[0] += 1
            if dir == Directions.North: c.North = 'TEST_VALUE' + str(cnt[0])
            if dir == Directions.South: c.South = 'TEST_VALUE' + str(cnt[0])
            if dir == Directions.East: c.East = 'TEST_VALUE' + str(cnt[0])
            if dir == Directions.West: c.West = 'TEST_VALUE' + str(cnt[0])
            assert c.getWall(dir) == 'TEST_VALUE' + str(cnt[0])
            c.setWall(dir, 'SECOND_TEST_VALUE' + str(cnt[0]))
            if dir == Directions.North: assert c.North == 'SECOND_TEST_VALUE' + str(cnt[0])
            if dir == Directions.South: assert c.South == 'SECOND_TEST_VALUE' + str(cnt[0])
            if dir == Directions.East: assert c.East == 'SECOND_TEST_VALUE' + str(cnt[0])
            if dir == Directions.West: assert c.West == 'SECOND_TEST_VALUE' + str(cnt[0])
        self.process(verify)

    def testChangeSignalOnWallChange(self):
        """Change signals should be fired when a cells walls are changed"""
        def verify(c, other, dir):
            pos = []
            def callback(cell): 
                pos.append(cell.pos)
            louie.connect(callback, 'change', c)
            louie.connect(callback, 'change', other)
            c.setWall(dir, 'TEST')
            assert pos.count(c.pos) == 1 and pos.count(other.pos) == 1 and len(pos) == 2
        self.process(verify)

    def testChangeSignalOnCellChange(self):
        """Change signals should be fired when a cells walls are changed"""
        def verify(c, other, dir):
            pos = []
            def callback(cell):
                pos.append(cell.pos)
            louie.connect(callback, 'change', c)
            c.value = 'TEST'
            assert pos.count(c.pos) == 1 and len(pos) == 1
        self.process(verify)

class MapPickle(unittest.TestCase):
    def setUp(self):
        m = Map()
        self.map = pickle.loads(pickle.dumps(m))

    def process(self, verify):
        for (x,y) in [(x,y) for y in range(self.map.height) for x in range(self.map.width)]:
            cur = self.map.getCell(x,y)
            if (x > 0): verify(cur, self.map.getCell(x - 1, y), Directions.West)
            if (x < self.map.width - 1): verify(cur, self.map.getCell(x + 1, y), Directions.East)
            if (y > 0): verify(cur, self.map.getCell(x, y - 1), Directions.North)
            if (y < self.map.height - 1): verify(cur, self.map.getCell(x, y + 1), Directions.South)

    def testChangeSignalOnWallChangeAfterPickle(self):
        """Change signals should be fired when a cells walls are changed - also after the map have been unpickled"""
        def verify(c, other, dir):
            pos = []
            def callback(cell): 
                pos.append(cell.pos)
            louie.connect(callback, 'change', c)
            louie.connect(callback, 'change', other)
            c.setWall(dir, 'TEST')
            assert pos.count(c.pos) == 1 and pos.count(other.pos) == 1 and len(pos) == 2
        self.process(verify)

class MapExpand(CellTest):
    def setUp(self):
        self.map = Map()
        self.map.expandWidth()
        self.map.expandHeight()

if __name__ == '__main__':
    unittest.main(testRunner=unittest.TextTestRunner(verbosity = 2))

